package com.qqs.distributed.advice;

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.StringUtils;

import java.lang.reflect.Type;


public class CacheAttributeWrapper {
    private CacheAttribute attribute;
    private Object[] args;
    private String key;
    private Type returnType;

    public CacheAttributeWrapper(CacheAttribute attribute, Object[] args) {
        this.attribute = attribute;
        this.args = args;
    }

    public CacheAttributeWrapper(CacheAttribute attribute, MethodInvocation invocation) {
        this.attribute = attribute;
        this.args = invocation.getArguments();
        determineReturnType(this, invocation);
    }

    public CacheAttribute getAttribute() {
        return attribute;
    }

    public Object[] getArgs() {
        return args;
    }

    public String getKey() {
        if (!StringUtils.hasLength(key)) {
            key = generateKey();
        }
        return key;
    }

    public Type getReturnType() {
        if (returnType == null) {
            return attribute.getReturnType();
        }
        return returnType;
    }

    public void setReturnType(Type returnType) {
        this.returnType = returnType;
    }

    private String generateKey() {
        if (!StringUtils.hasLength(attribute.getCacheKeyExpr())) {
            return attribute.getMethod().getName();
        }
        // 准备一个SpEl的解析器
        SpelExpressionParser parser = new SpelExpressionParser();
        // 让解析器解析我们指定的字符串
        Expression expression = parser.parseExpression(attribute.getCacheKeyExpr(), new TemplateParserContext());
        // 指定解析器上下文环境
        EvaluationContext context = new StandardEvaluationContext();
        context.setVariable("args", args);
        context.setVariable("method", attribute.getMethod());
        // context.setVariable("formatdate", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        String value = expression.getValue(context, String.class);
        return value;
    }

    /**
     * 如果返回值为Object类型,则在当前正在执行方法的实参中获取名为returnType并且为Type类型的参数值当做方法返回值的类型
     *
     * @param attributeWrapper
     * @param invocation
     */
    public void determineReturnType(CacheAttributeWrapper attributeWrapper,
                                    MethodInvocation invocation) {
        //
        if (invocation.getMethod().getReturnType() == Object.class) {
            ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
            String[] parameterNames = parameterNameDiscoverer.getParameterNames(invocation.getMethod());
            Object[] arguments = invocation.getArguments();
            for (int i = 0; i < parameterNames.length; i++) {
                if ("returnType".equals(parameterNames[i]) && arguments[i] instanceof Type) {
                    attributeWrapper.setReturnType((Type) arguments[i]);
                    return;
                }
            }
            attributeWrapper.setReturnType(attributeWrapper.getAttribute().getReturnType());
        }
    }
}
